/********************************************************************
 Program : Online Feature Selection.
 Author  : Nikhil R. Pal and K. Chintalapudi.
********************************************************************/

#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>
#include<time.h>

/*******************************************************************/
/*****************Global Variables Declaration *********************/

char	filename[100];
int	inpNode,hidNode,outNode;
long	iter=0,cntTrnData=0,STEP=0;
double	**wih,**pwih,**cwih,**who,**pwho,**cwho;
double	**trnData,**err,**doutTrn,**aoutput,**aoutput1;
double	*beta,*pbeta,*delta,*delta1,*delta_inp,*outdelta,*delbeta;
double 	*attenFun,*netValHid,*hidActiv,*netValOup,*outActiv;
double	n=0.7,mu=0.7;

/*******************************************************************/
/***************** Functions Declaration ***************************/

void	training();
void 	initialize();
void 	memory_free();
void 	Free(double ** , int );
void 	weight_initialization();
void 	writefile();
double	sigmoid(double );
double 	**memory2double(int ,int ,char * );
/*******************************************************************/

int main()
{
	initialize();
	training();	
	
	writefile();
	memory_free();
	
	return(0);	
}
/*******************************************************************/

void 	initialize()
{
	long 	i,j;
	FILE 	*fp;
	int	ch;
	
	printf("\n Enter the no of input nodes...");
	scanf("%d",&inpNode);
	
	printf("\n Enter the no of hidden nodes...");
	scanf("%d",&hidNode);
	
	printf("\n Enter the no of output nodes...");
	scanf("%d",&outNode);
	
	printf("\n Enter the no of iterations...");
	scanf("%d",&iter);
	
	printf("\n Enter the name of the input file...");
	scanf("%s",filename);
	
	printf("\n Enter the STEP size...");
	scanf("%d",&STEP);	
	
	fp = fopen(filename,"r");
	while(!feof(fp))
	{
		if((ch=fgetc(fp))=='\n')
			cntTrnData++;			
	}
	fclose(fp);
	
	trnData = memory2double(cntTrnData,inpNode+outNode,"trnData");
	
	/*********READING THE TRAINING FILE**************/
	
	fp = fopen(filename,"r");
	
	for(i = 0; i < cntTrnData; i++)
		for(j = 0; j <(inpNode+outNode); j++)
			fscanf(fp,"%lf",&trnData[i][j]);	
		
	fclose(fp);
	
	/***** INTIALIZING THE WEGHT OF THE NN ***************/			
	weight_initialization();
		
	return;	
}
/*******************************************************************/

void weight_initialization()
{
	long 	i,j;
	time_t	t;
	double	d;
	
	wih = memory2double(hidNode,inpNode,"wih");	
	cwih = memory2double(hidNode,inpNode,"cwih");
	pwih = memory2double(hidNode,inpNode,"pwih");
	
	who = memory2double(outNode,hidNode,"who");
	cwho = memory2double(outNode,hidNode,"cwho");
	pwho = memory2double(outNode,hidNode,"pwho");
	
	/****** MEMORY ALLOCATION TO STORE ATTENUATION VALUES ******/
	
	attenFun = (double*)calloc(inpNode,sizeof(double));
	beta = (double*)calloc(inpNode,sizeof(double));
	pbeta = (double*)calloc(inpNode,sizeof(double));	
	delta1 = (double*)calloc(hidNode,sizeof(double));
	delta = (double*)calloc(hidNode,sizeof(double));
	delta_inp =(double*)calloc(inpNode,sizeof(double));
	outdelta=(double*)calloc(outNode,sizeof(double));
	delbeta	=(double*)calloc(inpNode,sizeof(double));
	
	srand((unsigned)time(&t));
	
	for(i = 0;i <hidNode; i++)
	{
		for(j = 0 ; j <inpNode ; j++)
		{			
			d=(double)rand()/(RAND_MAX);
			wih[i][j]=d-0.5;
			pwih[i][j] = wih[i][j];			
		}		
	}
	
	srand((unsigned)time(&t));
	
	for(i = 0; i < outNode; i++)
	{
		for(j = 0 ; j < hidNode ; j++)
		{			
			d=(double)rand()/(RAND_MAX);
			who[i][j]=d-0.5;			
			pwho[i][j] = who[i][j];			
		}		
	}	
	
	for( i = 0; i < inpNode; i++)
	{
		beta[i] = -5.0;
		pbeta[i] = -5.0;
		attenFun[i] = sigmoid(beta[i]);
	}
	
	return;			
}
/*******************************************************************/

double **memory2double(int a,int b,char *s)
{
	double **temp;
	int i;
	
	temp = (double**)calloc(a,sizeof(double*));
	
	if(temp == NULL)
	{
		printf("\n Error %s\n",s);
		exit(0);
	}
	for(i = 0; i < a; i++)
	{
		temp[i] = (double*)calloc(b,sizeof(double));
		if(temp[i] == NULL)
		{
			printf("\n Error %s[%d]\n",s,i);
			exit(0);
		}
	}
	
	return(temp);
}
/*******************************************************************/

double sigmoid(double x)
{
	double sig;
	double d;
	d=exp(-x);
	d=d+1;
	sig = (double)(1/d);
	return(sig);
}
/*******************************************************************/

void training()
{	
	FILE	*fp;
	long 	i,j,k,maxacol,maxdcol;	
	char	statusfile[100];
	char	attenuation_file[100];	
	double 	*iv,temp,maxa,maxd;
	long	Misclsf=0,epoc=0;
	double	prevsse=0,sse=0;
	
	/**********************************************************/
	strcpy(statusfile,filename);
	strcat(statusfile,".status_feature.txt");
	
	strcpy(attenuation_file,filename);
	strcat(attenuation_file,".gate_val.txt");
	/************************************************************/
	fp = fopen(statusfile,"w");
	fclose(fp);
	
	fp = fopen(attenuation_file,"w");
	fclose(fp);
	
	/***DYNAMIC MEMORY ALLOCATION FOR THE DESIRED OUTPUT ARRAY**/
	doutTrn = memory2double(cntTrnData,outNode,"doutTrn");
	aoutput = memory2double(cntTrnData,outNode,"aoutput");
	aoutput1= memory2double(cntTrnData,outNode,"aoutput1");
	err	= memory2double(cntTrnData,outNode,"err");
	
	/***DYNAMIC MEMORY ALLOCATION FOR THE ACTIVATION VALUES*****/
	netValHid = (double*)calloc(hidNode,sizeof(double));
	hidActiv = (double*)calloc(hidNode,sizeof(double));	
	netValOup = (double*)calloc(outNode,sizeof(double));
	outActiv=(double*)calloc(outNode,sizeof(double));
	
	for(i = 0 ; i < cntTrnData ; i++)
		for(j=0 ; j<outNode; j++)
			doutTrn[i][j] = trnData[i][inpNode+j];			
			
	iv=(double *)calloc(inpNode,sizeof(double));	
	
	epoc = 0;
   	while(epoc<iter)
   	{	
		for(k=0;k<cntTrnData;k++)
		{
			for(i=0;i<inpNode;i++)
				iv[i]=trnData[k][i]*attenFun[i];
	
			/***  HIDDEN ACTIVATION CALCULATION ********/
			for(i=0;i<hidNode;i++)
			{	
				netValHid[i]=0;
				for(j=0;j<inpNode;j++)
					netValHid[i]+=iv[j]*wih[i][j];
				hidActiv[i]=sigmoid(netValHid[i]);
			}
		
	  		/*******   OUTPUT CALCULATION  *************/
	
			for(i=0;i<outNode;i++)
			{	
				netValOup[i]=0;
				for(j=0;j<hidNode;j++)
					netValOup[i]+=hidActiv[j]*who[i][j];
				outActiv[i]=sigmoid(netValOup[i]);
			}		
	
			/****** OUTPUT ERROR CALCULATION   *********/
	
			for(i=0;i<outNode;i++)
				err[k][i]=(doutTrn[k][i]-outActiv[i]);
			
			/*******  OUTPUT LAYER DELTA  **************/
		
			for(i=0;i<outNode;i++)
				outdelta[i]=err[k][i]*outActiv[i]*(1-outActiv[i]);
			
			/******  HIDDEN TO OUTPUT DELTA WEIGHT *****/
	
			for(i=0;i<outNode;i++)
				for(j=0;j<hidNode;j++)
		  		 	cwho[i][j]=n*outdelta[i]*hidActiv[j];

			/*****  HIDDEN LAYER DELTA CALCULATION *****/
			
			for(i=0;i<hidNode;i++)
			{
				delta[i]=0.0;
				
				for(j=0;j<outNode;j++)
					delta[i]+=outdelta[j]*who[j][i];
				
				delta[i]=delta[i]*hidActiv[i]*(1-hidActiv[i]);			
			}
	
			/******  INPUT TO HIDDEN DELTA WEIGHT ******/
	
			for(i=0;i<hidNode;i++)
				for(j=0;j<inpNode;j++)
					cwih[i][j]=n*delta[i]*iv[j];
						
			/****  ACTUAL INPUT TO ATTENUATE DELTA *****/
	
			for(j=0;j<inpNode;j++)
				delta_inp[j]=0.0;
			
			for(i=0;i<hidNode;i++)
				for(j=0;j<inpNode;j++)
					delta_inp[j]+=wih[i][j]*delta[i];
				
		
			for(j=0;j<inpNode;j++)
			{	
				temp = sigmoid(beta[j])*(1-sigmoid(beta[j]));
				delbeta[j]=mu*trnData[k][j]*temp*delta_inp[j];
			}
			
			/*****************  UPDATION ***************/
			/*********     UPDATION OF WHO     *********/
	
			for(i=0;i<outNode;i++)
				for(j=0;j<hidNode;j++)
					who[i][j]=who[i][j]+cwho[i][j];
				
			/**********   UPDATION OF WIH      *********/
	
			for(i=0;i<hidNode;i++)
				for(j=0;j<inpNode;j++)
					wih[i][j]=wih[i][j]+cwih[i][j];
							
			/******** UPDATION OF ATTENUATORS  *********/
	
			for(i=0;i<inpNode;i++)
			{
				beta[i]=beta[i]+delbeta[i];
				attenFun[i]=sigmoid(beta[i]);
			}
		}
		
		/****************** Section Copied *****************/
		/***************************************************/
		
		Misclsf = 0;
		sse = 0;								
		
		for(k = 0; k < cntTrnData; k++)
		{
			for(i = 0; i < hidNode; i++)
			{
				netValHid[i] = 0;
				hidActiv[i] = 0;
				
				for(j = 0 ; j < inpNode ; j++)
					netValHid[i]+= (wih[i][j]*(trnData[k][j] * attenFun[j]));
				
				hidActiv[i] = sigmoid(netValHid[i]);
			}
							
			for(i = 0; i < outNode; i++)
			{
				netValOup[i] = 0;
				aoutput1[k][i] = 0;
				
				for(j = 0 ; j < hidNode ; j++)
					netValOup[i]+= (who[i][j] * hidActiv[j]);
				
				aoutput1[k][i] = sigmoid(netValOup[i]);
				err[k][i] = doutTrn[k][i] - aoutput1[k][i];
				sse+= err[k][i] * err[k][i];
			}
			
		/*	if(epoc == 0 )
			{
				for(i=0 ; i<outNode ;i++)
					prevsse+= err[k][i] * err[k][i];													
			}
		*/		
			maxacol = -1;
			maxdcol = -1;
			maxa = -1;
			maxd = -1;
			
			for(i=0 ; i<(outNode) ;i++)
			{
				/* Change for Multiclass*/
				
				if(maxa<aoutput1[k][i])
				{
					maxa=aoutput1[k][i];
					maxacol=i;					
				}

				if(maxd<doutTrn[k][i])
				{
					maxd=doutTrn[k][i];
					maxdcol=i;					
				}				
			}	
			
			if(maxdcol!=maxacol)
				Misclsf++;							
		}
		
	     /*	if(sse > prevsse)
		{			
			for(i = 0 ; i < hidNode ; i++)
				for(j = 0 ;j < inpNode ; j++)
					wih[i][j] = pwih[i][j];					
							
			for(i = 0 ;i < outNode ; i++)
				for(j = 0 ; j < hidNode ; j++)
					who[i][j] = pwho[i][j];
				
			for(i=0 ; i<inpNode ; i++)
			{
				beta[i] = pbeta[i];
				attenFun[i] = sigmoid(beta[i]);
			}			
						
			n=0.95*n;
			mu=0.95*mu;
			
			epoc--;
			
			sse=prevsse;			
		}
		
		else if(sse <= prevsse)
		
		{
		*/
			prevsse = sse;
			for(i = 0 ; i < outNode ; i++)
				for(j = 0 ;j < hidNode ; j++)
					pwho[i][j] = who[i][j];
				
			for(i = 0 ;i < hidNode ; i++)
				for(j = 0 ; j < inpNode ; j++)
					pwih[i][j] = wih[i][j];
				
			for(i=0 ; i<inpNode ; i++)
				pbeta[i] = beta[i];				
		/* } */	
		
		if((epoc % STEP) == 0)
		{
			printf("\nEpoch= %d",epoc);
			printf("\n sse = %lf",sse);
			printf("\n Misclas = %d ",Misclsf);
			printf("\n Learning parameter = %lf",n);
			printf("\n learning parameter for attenfun = %lf\n",mu);
	/*		for(i = 0; i < inpNode; i++)
				printf(" af[%d] = %lf\n",i,attenFun[i]);
	*/	
			fp=fopen(statusfile,"a");

			fprintf(fp,"%d  %d  %lf %lf\n", epoc,Misclsf,sse,n);
			fclose(fp);
			
			fp=fopen(attenuation_file,"a");
			for(i=0; i<inpNode-1; i++)
				fprintf(fp,"%lf  ",attenFun[i]);
			fprintf(fp,"%lf\n",attenFun[i]);
			fclose(fp);			
		}
	
		epoc++;
	}
	
	free(iv);	
	return;	
}
/*******************************************************************/

void writefile()
{
	FILE 	*fp1,*fp2;
	char 	filename1[200],filename2[200];
	int 	i,k,k1;	
	double 	maxa,maxd;
	int 	maxacol,maxdcol; 
	
	strcpy(filename1,filename);
	strcat(filename1,".pre.txt");
	
	strcpy(filename2,filename);
	strcat(filename2,".act.txt");
	fp1=fopen(filename1,"w");	
	fp2=fopen(filename2,"w");
	
	for(k=0;k<cntTrnData;k++)
	{
		maxa=-1,maxd=-1;
		maxacol=-1,maxdcol=-1; 
		
		for(i=0 ; i<(outNode) ;i++)
		{			
			if(maxa<aoutput1[k][i])
			{
				maxa=aoutput1[k][i];
				maxacol=i;
			}

			if(maxd<doutTrn[k][i])
			{
				maxd=doutTrn[k][i];
				maxdcol=i;
			}
		}	

		if(maxacol!=maxdcol)
		{
			for(k1=0;k1<outNode;k1++)
				fprintf(fp1,"%lf\t",aoutput1[k][k1]);
			fprintf(fp1,"\n");
				
			for(k1=0;k1<outNode;k1++)
				fprintf(fp2,"%lf\t",doutTrn[k][k1]);
			fprintf(fp2,"\n");
		}		
	}	
	
	fclose(fp1);
	fclose(fp2);
	
	return;
}
/*******************************************************************/

void memory_free()
{
	Free(wih,hidNode);
	Free(cwih,hidNode);
	Free(pwih,hidNode);
	Free(who,outNode);
	Free(cwho,outNode);
	Free(pwho,outNode);
	free(attenFun);
	free(beta);
	free(pbeta);
	free(delta1);
	free(delta);
	free(delta_inp);
	Free(trnData,cntTrnData);
	Free(doutTrn,cntTrnData);
	Free(aoutput,cntTrnData);
	Free(aoutput1,cntTrnData);
	Free(err,cntTrnData);
	free(netValHid);
	free(hidActiv);
	free(netValOup);
	
	return;	
}	
/*******************************************************************/

void Free(double **node, int a)
{
	int i;
	
	for(i=0;i<a;i++)
		free(node[i]);
	
	free(node);
	return;
}
/*******************************************************************/

